﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;

namespace Dotway.WPF.Effects
{
    /// <summary>
    /// Create a transformation to/from a Sine-wave.
    /// </summary>
    public class WaveEffectTransform : GeneralTransform, ICloneable
    {
        public WaveEffectTransform()
        { }


        public static readonly DependencyProperty FrequencyProperty = DependencyProperty.Register("Frequency", typeof(double), typeof(WaveEffectTransform), new PropertyMetadata(1.0), new ValidateValueCallback(IsValidFrequency));
        public double Frequency
        {
            get { return (double)GetValue(FrequencyProperty); }
            set { SetValue(FrequencyProperty, value); }
        }

        public static bool IsValidFrequency(object value)
        {
            double checkValue = (double)value;

            if (checkValue < 0.0)
            {
                return false;
            }

            return true;
        }


        public static readonly DependencyProperty AmplitudeProperty = DependencyProperty.Register("Amplitude", typeof(double), typeof(WaveEffectTransform), new PropertyMetadata(0.2), new ValidateValueCallback(IsValidAmplitude));
        public double Amplitude
        {
            get { return (double)GetValue(AmplitudeProperty); }
            set { SetValue(AmplitudeProperty, value); }
        }

        public static bool IsValidAmplitude(object value)
        {
            double checkValue = (double)value;

            if (checkValue < 0.0)
            {
                return false;
            }

            return true;
        }

        private bool _isInverse = false;
        private bool IsInverse
        {
            get { return _isInverse; }
            set { _isInverse = value; }
        }

        public override GeneralTransform Inverse
        {
            get
            {
                WaveEffectTransform newWaveTransform = (WaveEffectTransform)this.Clone();
                newWaveTransform.IsInverse = !IsInverse;
                return newWaveTransform;
            }
        }

        /// <summary>
        /// Transform a bounding box to/from Sin-wave.
        /// </summary>
        /// <param name="rect"></param>
        /// <returns></returns>
        public override Rect TransformBounds(Rect rect)
        {
            Rect boundingBox = rect;

            if (IsInverse)
            {
                boundingBox.Y = rect.Y - Amplitude;
                boundingBox.Height = rect.Height + (2 * Amplitude);
            }
            else
            {
                boundingBox.Y = rect.Y + Amplitude;
                boundingBox.Height = rect.Height - (2 * Amplitude);
            }
            return boundingBox;
        }

        /// <summary>
        /// Transform a point to/from the Sin-wave. Use Inverse to get the inverse transformation
        /// of the Sine-wave.
        /// </summary>
        /// <param name="inPoint"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public override bool TryTransform(Point inPoint, out Point result)
        {
            result = new Point();

            if (IsInverse)
            {
                result.Y = inPoint.Y + (Math.Sin(inPoint.X * Frequency) * Amplitude);
                result.X = inPoint.X;
            }
            else
            {
                result.Y = inPoint.Y - (Math.Sin(inPoint.X * Frequency) * Amplitude);
                result.X = inPoint.X;
            }
            return true;
        }

        protected override Freezable CreateInstanceCore()
        {
            return new WaveEffectTransform();
        }

        protected override void CloneCore(Freezable sourceFreezable)
        {
            WaveEffectTransform newWaveTransform = (WaveEffectTransform)sourceFreezable;
            base.CloneCore(newWaveTransform);
            this.CopyCommon(newWaveTransform);
        }

        #region ICloneable Members

        public new object Clone()
        {
            WaveEffectTransform newWaveTransform = new WaveEffectTransform();
            newWaveTransform.CopyCommon(this);

            return newWaveTransform;
        }

        #endregion ICloneable Members

        private void CopyCommon(WaveEffectTransform transform)
        {
            this.IsInverse = transform.IsInverse;
            this.Frequency = transform.Frequency;
            this.Amplitude = transform.Amplitude;
        }
    }
}
